using System;
using System.Collections.Generic;
using System.Text;
using BizTalkCop.Rules.Bases;
using Microsoft.FxCop.Sdk;
using BizTalkCop.Rules.Enums;
using System.Xml.XPath;
using System.Xml;
using BizTalkCop.Rules.Helpers;

namespace BizTalkCop.Rules.Naming.Rules
{
    /// <summary>
    /// Rule verifying that orchestration members are camel cased
    /// </summary>
    /// <remarks>
    /// Checks members declarations for: ports, messages, correlation sets, role links and variables
    /// </remarks>
    public class OrchestrationMembersShouldBeCamelCased : OrchestrationRuleBase
    {
        /// <summary>
        /// Default constructor
        /// </summary>
        public OrchestrationMembersShouldBeCamelCased() : base("OrchestrationMembersShouldBeCamelCased") { }

        private static Dictionary<OMElementType, string> _types;
        private static Dictionary<OMElementType, string> Types
        {
            get
            {
                if (_types == null)
                {
                    _types = new Dictionary<OMElementType, string>();
                    _types.Add(OMElementType.PortDeclaration, "Port");
                    _types.Add(OMElementType.MessageDeclaration, "Message");
                    _types.Add(OMElementType.CorrelationDeclaration, "Correlation Set");
                    _types.Add(OMElementType.ServiceLinkDeclaration, "Role Link");
                    _types.Add(OMElementType.VariableDeclaration, "Variable");
                }
                return _types;
            }
        }

        /// <summary>
        /// Checks if the orchestration's members are camel cased
        /// </summary>
        /// <param name="type">Type to check</param>
        /// <returns>Problem collection</returns>
        public override ProblemCollection Check(TypeNode type)
        {
            if (IsOrchestration(type))
            {
                foreach (KeyValuePair<OMElementType, string> elementType in Types)
                {
                    XPathNodeIterator elements = GetOMElements(type, elementType.Key);
                    this.CheckElements(elements, elementType.Key, elementType.Value, type);
                }
            }
            return Problems;
        }

        private void CheckElements(XPathNodeIterator elements, OMElementType elementType, string elementTypeName, TypeNode type)
        {
            foreach (XPathNavigator navigator in elements)
            {
                string name = SelectSingleNode(navigator, XPathQuery.OMNamePropertyNode).Value;
                //parameters are typed as Variable Declarations so check if parent = ServiceBody:
                if (elementType == OMElementType.VariableDeclaration)
                {
                    string id = SelectSingleNode(navigator, XPathQuery.OMIdNode).Value;
                    string parentType = SelectSingleNode(navigator, string.Format(XPathQuery.OMParentTypeByIdFormat, id)).Value;
                    OMElementType parentElementType = EnumHelper.Parse<OMElementType>(parentType);
                    if (parentElementType == OMElementType.ServiceBody)
                    {
                        elementTypeName = "Parameter";
                    }
                }
                if (!MemberName.IsCamelCase(name))
                {
                    Problems.Add(new Problem(GetNamedResolution("Case", elementTypeName, name, MemberName.ToCamelCase(name)), type));
                }
            }
        }
    }
}
